/* Susan(tm) Java Version
   by Thomas Lochmatter, Brig-Glis, Switzerland
   and Patrick Bizeau, Brig-Glis, Switzerland    */
   
package laWa;
import java.io.*;

// Contains the information about one entry in the database
class SusanDBEntry implements Comparable {

  // ######################### INSTANCE VARIABLES

  // This is the rotation matrix
  // It could be calculated each time, but this is much faster
  public static final int[] rot={ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,
                                  55,44,33,22,11,0,19,19,19,19,19,67,56,45,34,23,12,1,19,19,19,19,79,68,57,46,35,24,13,2,19,19,19,91,80,69,58,47,36,25,14,3,19,19,103,92,81,70,59,48,37,26,15,4,19,115,104,93,82,71,60,49,38,27,16,5,19,116,105,94,83,72,61,50,39,28,17,19,19,117,106,95,84,73,62,51,40,29,19,19,19,118,107,96,85,74,63,52,41,19,19,19,19,119,108,97,86,75,64,53,19,19,19,19,19,120,109,98,87,76,65,
                                  115,103,91,79,67,55,19,19,19,19,19,116,104,92,80,68,56,44,19,19,19,19,117,105,93,81,69,57,45,33,19,19,19,118,106,94,82,70,58,46,34,22,19,19,119,107,95,83,71,59,47,35,23,11,19,120,108,96,84,72,60,48,36,24,12,0,19,109,97,85,73,61,49,37,25,13,1,19,19,98,86,74,62,50,38,26,14,2,19,19,19,87,75,63,51,39,27,15,3,19,19,19,19,76,64,52,40,28,16,4,19,19,19,19,19,65,53,41,29,17,5,
                                  120,119,118,117,116,115,19,19,19,19,19,109,108,107,106,105,104,103,19,19,19,19,98,97,96,95,94,93,92,91,19,19,19,87,86,85,84,83,82,81,80,79,19,19,76,75,74,73,72,71,70,69,68,67,19,65,64,63,62,61,60,59,58,57,56,55,19,53,52,51,50,49,48,47,46,45,44,19,19,41,40,39,38,37,36,35,34,33,19,19,19,29,28,27,26,25,24,23,22,19,19,19,19,17,16,15,14,13,12,11,19,19,19,19,19,5,4,3,2,1,0,
                                  65,76,87,98,109,120,19,19,19,19,19,53,64,75,86,97,108,119,19,19,19,19,41,52,63,74,85,96,107,118,19,19,19,29,40,51,62,73,84,95,106,117,19,19,17,28,39,50,61,72,83,94,105,116,19,5,16,27,38,49,60,71,82,93,104,115,19,4,15,26,37,48,59,70,81,92,103,19,19,3,14,25,36,47,58,69,80,91,19,19,19,2,13,24,35,46,57,68,79,19,19,19,19,1,12,23,34,45,56,67,19,19,19,19,19,0,11,22,33,44,55,
                                  5,17,29,41,53,65,19,19,19,19,19,4,16,28,40,52,64,76,19,19,19,19,3,15,27,39,51,63,75,87,19,19,19,2,14,26,38,50,62,74,86,98,19,19,1,13,25,37,49,61,73,85,97,109,19,0,12,24,36,48,60,72,84,96,108,120,19,11,23,35,47,59,71,83,95,107,119,19,19,22,34,46,58,70,82,94,106,118,19,19,19,33,45,57,69,81,93,105,117,19,19,19,19,44,56,68,80,92,104,116,19,19,19,19,19,55,67,79,91,103,115,
                                  0,11,22,33,44,55,66,77,88,99,110,1,12,23,34,45,56,67,78,89,100,111,2,13,24,35,46,57,68,79,90,101,112,3,14,25,36,47,58,69,80,91,102,113,4,15,26,37,48,59,70,81,92,103,114,5,16,27,38,49,60,71,82,93,104,115,6,17,28,39,50,61,72,83,94,105,116,7,18,29,40,51,62,73,84,95,106,117,8,19,30,41,52,63,74,85,96,107,118,9,20,31,42,53,64,75,86,97,108,119,10,21,32,43,54,65,76,87,98,109,120,
                                  5,4,3,2,1,0,89,89,89,89,89,17,16,15,14,13,12,11,89,89,89,89,29,28,27,26,25,24,23,22,89,89,89,41,40,39,38,37,36,35,34,33,89,89,53,52,51,50,49,48,47,46,45,44,89,65,64,63,62,61,60,59,58,57,56,55,89,76,75,74,73,72,71,70,69,68,67,89,89,87,86,85,84,83,82,81,80,79,89,89,89,98,97,96,95,94,93,92,91,89,89,89,89,109,108,107,106,105,104,103,89,89,89,89,89,120,119,118,117,116,115,
                                  65,53,41,29,17,5,89,89,89,89,89,76,64,52,40,28,16,4,89,89,89,89,87,75,63,51,39,27,15,3,89,89,89,98,86,74,62,50,38,26,14,2,89,89,109,97,85,73,61,49,37,25,13,1,89,120,108,96,84,72,60,48,36,24,12,0,89,119,107,95,83,71,59,47,35,23,11,89,89,118,106,94,82,70,58,46,34,22,89,89,89,117,105,93,81,69,57,45,33,89,89,89,89,116,104,92,80,68,56,44,89,89,89,89,89,115,103,91,79,67,55,
                                  120,109,98,87,76,65,89,89,89,89,89,119,108,97,86,75,64,53,89,89,89,89,118,107,96,85,74,63,52,41,89,89,89,117,106,95,84,73,62,51,40,29,89,89,116,105,94,83,72,61,50,39,28,17,89,115,104,93,82,71,60,49,38,27,16,5,89,103,92,81,70,59,48,37,26,15,4,89,89,91,80,69,58,47,36,25,14,3,89,89,89,79,68,57,46,35,24,13,2,89,89,89,89,67,56,45,34,23,12,1,89,89,89,89,89,55,44,33,22,11,0,
                                  115,116,117,118,119,120,89,89,89,89,89,103,104,105,106,107,108,109,89,89,89,89,91,92,93,94,95,96,97,98,89,89,89,79,80,81,82,83,84,85,86,87,89,89,67,68,69,70,71,72,73,74,75,76,89,55,56,57,58,59,60,61,62,63,64,65,89,44,45,46,47,48,49,50,51,52,53,89,89,33,34,35,36,37,38,39,40,41,89,89,89,22,23,24,25,26,27,28,29,89,89,89,89,11,12,13,14,15,16,17,89,89,89,89,89,0,1,2,3,4,5,
                                  55,67,79,91,103,115,89,89,89,89,89,44,56,68,80,92,104,116,89,89,89,89,33,45,57,69,81,93,105,117,89,89,89,22,34,46,58,70,82,94,106,118,89,89,11,23,35,47,59,71,83,95,107,119,89,0,12,24,36,48,60,72,84,96,108,120,89,1,13,25,37,49,61,73,85,97,109,89,89,2,14,26,38,50,62,74,86,98,89,89,89,3,15,27,39,51,63,75,87,89,89,89,89,4,16,28,40,52,64,76,89,89,89,89,89,5,17,29,41,53,65};

  // The field to compare to
  public int[] field = {0,0,0,0,0,0,0,0,0,0,0,
                        0,4,4,4,4,4,0,0,0,0,0,
                        0,4,4,4,4,4,4,0,0,0,0,
                        0,4,4,4,4,4,4,4,0,0,0,
                        0,4,4,4,4,4,4,4,4,0,0,
                        0,4,4,4,4,4,4,4,4,4,0,
                        0,0,4,4,4,4,4,4,4,4,0,
                        0,0,0,4,4,4,4,4,4,4,0,
                        0,0,0,0,4,4,4,4,4,4,0,
                        0,0,0,0,0,4,4,4,4,4,0,
                        0,0,0,0,0,0,0,0,0,0,0,};

  // Some additional information
  public int[] movefrom;
  public int[] moveto;
  public int[] movepoints;
  public String nam;
  public int maxstones;
  public int minstones;

  // ######################### CONSTRUCTOR

  // Creates a void entry
  SusanDBEntry() {
    movefrom=new int[0];
    moveto=new int[0];
    movepoints=new int[0];
    nam="new Entry";
  }

  // Creates a copy of an entry
  SusanDBEntry(SusanDBEntry sdbe) {
    int count=sdbe.movefrom.length;
    movefrom=new int[count];
    moveto=new int[count];
    movepoints=new int[count];
    for (int i=0; i<count; i++) {
      movefrom[i]=sdbe.movefrom[i];
      moveto[i]=sdbe.moveto[i];
      movepoints[i]=sdbe.movepoints[i];
    }
    for (int i=0; i<121; i++) {
      field[i]=sdbe.field[i];
    }
    minstones=sdbe.minstones;
    maxstones=sdbe.maxstones;
    nam=sdbe.nam;
  }

  // Reads a new entry from a file
  SusanDBEntry(DataInputStream in) {
    int count;
    int i;
    int ex;
    try {
      nam=in.readUTF();
      for (i=0; i<121; i++) {
        ex=(field[i] & SusanGame.fieldexists);
        field[i]=in.readInt() | SusanGame.fieldexists;
        if (ex==0) {field[i]^=SusanGame.fieldexists;}
        if ((field[i]&SusanGame.fieldexoccupied)==SusanGame.fieldexoccupiedno) {
          field[i]&=SusanGame.fieldexoccupied|SusanGame.fielddontcare;
        } else {
          field[i]&=SusanGame.fieldexoccpl|SusanGame.fielddontcare;
        }
      }
      count=in.readInt();
      movefrom=new int[count];
      moveto=new int[count];
      movepoints=new int[count];
      for (i=0; i<count; i++) {
        movefrom[i]=in.readInt();
        moveto[i]=in.readInt();
        movepoints[i]=in.readInt();
      }
      minstones=in.readInt();
      maxstones=in.readInt();
    } catch (EOFException e) {
      field=null;
    } catch (IOException e) {
      field=null;
    }
  }

  // ######################### VARIOUS METHODS

  // Saves this entry
  public void saveEntry(DataOutputStream out) {
    int count;
    int i;
    try {
      out.writeUTF(nam);
      for (i=0; i<121; i++) {
        out.writeInt(field[i]);
      }
      count=movefrom.length;
      out.writeInt(count);
      for (i=0; i<count; i++) {
        out.writeInt(movefrom[i]);
        out.writeInt(moveto[i]);
        out.writeInt(movepoints[i]);
      }
      out.writeInt(minstones);
      out.writeInt(maxstones);
    } catch (IOException e) {
    }
  }

  // Returns the values as string
  public String toString() {
    int count=movefrom.length;
    StringBuffer t=new StringBuffer("");
    for (int i=0; i<count; i++) {
      if (movefrom[i]==SusanGame.magicfield) {
        t.append(SusanGame.toString(moveto[i])+"    ");
      } else {
        t.append(SusanGame.toString(movefrom[i])+" "+SusanGame.toString(moveto[i])+" ");
      }
      String tt=Integer.toString(movepoints[i]);
      int nn=6-tt.length();
      for (int n=0; n<nn; n++) {
        t.append(" ");
      }
      t.append(tt+"\n");
    }
    if (maxstones!=0) {
      t.append("\nstones "+minstones+" "+maxstones+"\n");
    } else if (minstones!=0) {
      t.append("\nstones "+minstones+"\n");
    }
    return t.toString();
  }

  // Splits a string and stores the new values
  public void fromString(String t) {
    int mfrom[]=new int[20];
    int mto[]=new int[20];
    int mpoints[]=new int[20];
    int mi=0;

    t=t+"\n";
    String arg[]=new String[3];
    int argi=0;
    char[] buff=new char[10];
    int buffi=0;
    int count=t.length();
    int i=0;
    while (i<count) {
      char thischar=t.charAt(i);
      if ((thischar==10) || (thischar==32) || (thischar==9)) {
        if (buffi>0) {
          if (argi<3) {
            arg[argi]=new String(buff,0,buffi);
            argi++;
          }
          buffi=0;
        }
      }
      if (thischar==10) {
        if (argi==3) {
          if (arg[0].toLowerCase().equals("stones")) {
            try {minstones=Integer.parseInt(arg[1]);} catch (NumberFormatException e) {}
            try {maxstones=Integer.parseInt(arg[2]);} catch (NumberFormatException e) {}
          } else {
            mfrom[mi]=SusanGame.getPosition(arg[0]);
            mto[mi]=SusanGame.getPosition(arg[1]);
            try {mpoints[mi]=Integer.parseInt(arg[2]);} catch (NumberFormatException e) {}
            if ((mi<19) && ((field[mfrom[mi]] & SusanGame.fieldexists)!=0) && ((field[mto[mi]] & SusanGame.fieldexists)!=0)) {mi++;}
          }
        } else if (argi==2) {
          if (arg[0].toLowerCase().equals("stones")) {
            try {minstones=Integer.parseInt(arg[1]);} catch (NumberFormatException e) {}
            maxstones=0;
          } else {
            mfrom[mi]=SusanGame.magicfield;
            mto[mi]=SusanGame.getPosition(arg[0]);
            try {mpoints[mi]=Integer.parseInt(arg[1]);} catch (NumberFormatException e) {}
            if ((mi<19) && ((field[mto[mi]] & SusanGame.fieldexists)!=0)) {mi++;}
          }
        }
        argi=0;
      }
      if (((thischar>=48) && (thischar<=57)) || ((thischar>=65) && (thischar<=92)) || ((thischar>=97) && (thischar<=124)) || (thischar==45)) {
        buff[buffi]=thischar;
        if (buffi<9) {buffi++;}
      }
      i++;
    }

    movefrom=new int[mi];
    moveto=new int[mi];
    movepoints=new int[mi];
    for (i=0; i<mi; i++) {
      movefrom[i]=mfrom[i];
      moveto[i]=mto[i];
      movepoints[i]=mpoints[i];
    }
  }

  // Compares the situation from one of the player's point of view
  // doesn't take care if other bits in fl[] are set
  public int compare(int[] fl, int playturn) {
    boolean ok=true;
    int n;
    int rotn;
    int i;

    for (int r=0; r<12; r++) {
      n=r*121;
      ok=true;
      for (i=0; i<121; i++) {
        if ((field[i] & SusanGame.fielddontcare)==0) {
          if ((field[i] & SusanGame.fieldexoccupied)==SusanGame.fieldexoccupiedyes) {
            if (field[i]!=((fl[rot[n]]&SusanGame.fieldexoccpl)^playturn)) {ok=false; break;}
          } else {
            if (field[i]!=(fl[rot[n]]&SusanGame.fieldexoccupied)) {ok=false; break;}
          }
        }
        n++;
      }
      if (ok) {return r;}
    }
    return -1;
  }

  // Gets a movefrom value, rotated by r
  public int getmovefrom(int i, int r) {
    return SusanDBEntry.rot[r*121+movefrom[i]];
  }

  // Gets a moveto value, rotated by r
  public int getmoveto(int i, int r) {
    return SusanDBEntry.rot[r*121+moveto[i]];
  }

  // ######################### INTERFACE COMPARABLE
  // Comparator
  public int compareTo(Object o) {
    return nam.compareTo(((SusanDBEntry)o).nam);
  }
}

// ######################### END OF FILE
